package com.common.util.utils.bitmap;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.ExifInterface;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;

import com.common.util.utils.DiskUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;

public class BitmapUtils {


    public static final String EXTENSION_IMG_PNG = "png";
    public static final String EXTENSION_IMG_JPEG = "jpg";
    private final static int BITMAP_SIZE_LIMIT = 640 * 640;

    public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 图片裁剪
     * @param bitmap
     * @return
     */
    public static Bitmap crop(Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }

        final int height = bitmap.getHeight();
        final int width = bitmap.getWidth();
        if (height == width) {
            return bitmap;
        }

        final int cropSize = Math.min(width, height);
        final Bitmap result =
                Bitmap.createBitmap(bitmap, (width - cropSize) >> 1, (height - cropSize) >> 1, cropSize,
                        cropSize);

        return result;
    }

    public static Bitmap getThumbnailFromFile(String srcFile, int maxImageSize) {
        if (srcFile == null || srcFile.length() == 0) {
            return null;
        }

        BitmapFactory.Options op = new BitmapFactory.Options();
        op.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcFile, op);

        int width = op.outWidth;
        int height = op.outHeight;

        if (width * height <= maxImageSize) {
            Bitmap bitmapSmall = BitmapFactory.decodeFile(srcFile);
            return bitmapSmall;
        }

        int ratio =
                Math.round((float) Math.floor(Math.sqrt((float) width * (float) height / maxImageSize)));

        op.inSampleSize = ratio;
        op.inJustDecodeBounds = false;
        Bitmap bitmapSmall = BitmapFactory.decodeFile(srcFile, op);
        return bitmapSmall;
    }

    public static Bitmap loadFileFast(String path) throws OutOfMemoryError {
        if (path == null) {
            return null;
        }

        InputStream is = null;
        try {
            is = new FileInputStream(path);
            return BitmapFactory.decodeStream(is, null, null);
        } catch (final Exception e) {
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (final IOException e) {
                }
                is = null;
            }
        }

        return null;
    }

    public static Bitmap loadImage(String path) throws OutOfMemoryError {
        return loadImage(path, BITMAP_SIZE_LIMIT, null);
    }

    public static Bitmap loadImage(String path, int bitmapSizeLimit, Config bitmapConfig)
            throws OutOfMemoryError {
        if (path == null) {
            return null;
        }

        final File file = new File(path);
        if (!file.exists()) {
            return null;
        }
        InputStream is1 = null;
        InputStream is2 = null;
        try {
            is1 = new FileInputStream(path);
            final BitmapFactory.Options ops = new BitmapFactory.Options();
            ops.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is1, null, ops);
            try {
                is1.close();
            } catch (final Exception e) {
            }
            is1 = null;

            if (ops.outWidth > 0 && ops.outHeight > 0) {
                ops.inJustDecodeBounds = false;
                ops.inSampleSize = 1;
                int size = ops.outWidth * ops.outHeight;
                while (size > bitmapSizeLimit) {
                    ops.inSampleSize <<= 1;
                    size >>= 2;
                }

                if (bitmapConfig != null) {
                    ops.inPreferredConfig = bitmapConfig;
                }

                is2 = new FileInputStream(path);
                return BitmapFactory.decodeStream(is2, null, ops);
            }
        } catch (final Exception e) {
        } finally {
            if (is1 != null) {
                try {
                    is1.close();
                } catch (final IOException e) {
                }
                is1 = null;
            }
            if (is2 != null) {
                try {
                    is2.close();
                } catch (final IOException e) {
                }
                is2 = null;
            }
        }

        return null;
    }


    /**
     * 将原图片转换为对应尺寸，对应配置的图片
     * @param origin
     * @param newWidth
     * @param newHeight
     * @return 返回新图片, 失败返回为空
     */
    public static Bitmap zoomImage(Bitmap origin, int newWidth, int newHeight)
            throws OutOfMemoryError {

        if (origin == null || origin.isRecycled()) {
            return null;
        }

        int width = origin.getWidth();
        int height = origin.getHeight();
        if (width > 0 && height > 0 && newWidth > 0 && newHeight > 0) {
            Matrix matrix = new Matrix();
            float scalWidth = (float) newWidth/width;
            float scalHeight = (float) newHeight/height;
            matrix.postScale(scalWidth, scalHeight);
            Bitmap bitmap = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, true);
            return bitmap;
        } else {
            return origin;
        }

    }


    public static Bitmap loadUri(Context ctx, Uri imageUri) throws OutOfMemoryError {
        if (imageUri == null || ctx == null) {
            return null;
        }

        final ContentResolver cr = ctx.getContentResolver();

        InputStream is1 = null;
        InputStream is2 = null;
        try {
            is1 = cr.openInputStream(imageUri);

            final BitmapFactory.Options ops = new BitmapFactory.Options();
            ops.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is1, null, ops);
            try {
                is1.close();
            } catch (final IOException e) {
            }
            is1 = null;

            if (ops.outWidth > 0 && ops.outHeight > 0) {
                ops.inJustDecodeBounds = false;
                ops.inSampleSize = 1;
                int size = ops.outWidth * ops.outHeight;
                while (size > BITMAP_SIZE_LIMIT) {
                    ops.inSampleSize <<= 1;
                    size >>= 2;
                }

                is2 = cr.openInputStream(imageUri);
                return BitmapFactory.decodeStream(is2, null, ops);
            }
        } catch (final Exception e) {
        } finally {
            if (is1 != null) {
                try {
                    is1.close();
                } catch (final IOException e) {
                }
                is1 = null;
            }
            if (is2 != null) {
                try {
                    is2.close();
                } catch (final IOException e) {
                }
                is2 = null;
            }
        }

        return null;
    }

    public static Bitmap round(Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }

        Bitmap cropped = crop(bitmap);
        if (cropped == null) {
            return null;
        }

        int width = cropped.getWidth();

        float roundPx = width / 2;
        float top = 0;
        float bottom = width;
        float left = 0;
        float right = width;
        float dst_left = 0;
        float dst_top = 0;
        float dst_right = width;
        float dst_bottom = width;

        Bitmap output = Bitmap.createBitmap(width, width, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final int color = 0xFFFFFFFF;
        final Paint paint = new Paint();
        final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
        final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
        final RectF rectF = new RectF(dst);
        paint.setAntiAlias(true);
        paint.setColor(color);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(cropped, src, dst, paint);

        cropped.recycle();
        cropped = null;
        return output;
    }

    public static boolean save(Bitmap bitmap, String path) {
        return save(bitmap, path, 100);
    }

    public static boolean save(Bitmap bitmap, String path, int compress) {
        if (bitmap == null || path == null) {
            return false;
        }

        if(!DiskUtils.isSDCardReady()|| DiskUtils.getSDCardFreeSize() < 10 * 1024){
            return false;
        }

        final int indexFolder = path.lastIndexOf("/");
        if (indexFolder > 0) {
            final String folder = path.substring(0, indexFolder);
            final File folderFile = new File(folder);
            folderFile.mkdirs();
        }

        final File file = new File(path);
        if (file.exists()) {
            final boolean deleted = file.delete();
            if (!deleted) {
                return false;
            }
        }

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            //final boolean hasAlpha = bitmap.hasAlpha();
            return bitmap.compress(CompressFormat.JPEG, compress, fos);
        } catch (final Exception e) {
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (final IOException e) {
                }
                fos = null;
            }
        }

        return false;
    }

    public static Bitmap scale(Bitmap bitmap, float ratio) {
        if (bitmap == null || ratio <= 0.0f) {
            return null;
        }

        final int width = bitmap.getWidth();
        final int height = bitmap.getHeight();

        final Matrix matrix = new Matrix();
        matrix.setScale(ratio, ratio);
        final Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

        return result;
    }

    private BitmapUtils() {

    }

    /**
     * 缩放图片
     *
     * @param bitmap
     * @return
     */
    public static Bitmap zoom(Bitmap bitmap, float zf) {
        Matrix matrix = new Matrix();
        matrix.postScale(zf, zf);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
    }

    /**
     * 缩放图片
     *
     * @param bitmap
     * @return
     */
    public static Bitmap zoom(Bitmap bitmap, float wf, float hf) {
        Matrix matrix = new Matrix();
        matrix.postScale(wf, hf);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
    }

    /**
     * 图片圆角处理
     *
     * @param bitmap
     * @param roundPX
     * @return
     */
    public static Bitmap getRCB(Bitmap bitmap, float roundPX) {
        // RCB means
        // Rounded
        // Corner Bitmap
        Bitmap dstbmp = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(dstbmp);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPX, roundPX, paint);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return dstbmp;
    }

    /**
     * 将字符串转为bitmap
     *
     * @param imgInfo
     * @return
     */
    public static Bitmap string2Image(String imgInfo) {
        if (imgInfo == null) {
            return null;
        }
        Bitmap picture = null;
        byte[] decodeFast;
        ByteArrayInputStream bais = null;
        SoftReference<Bitmap> softRef = null;
        try {
            decodeFast = Base64.decode(imgInfo, Base64.DEFAULT);
            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(decodeFast, 0, decodeFast.length, options);
            options.inSampleSize = calcSampleSize(options, 600, 800);

            options.inJustDecodeBounds = false;
            bais = new ByteArrayInputStream(decodeFast);
            softRef = new SoftReference<Bitmap>(BitmapFactory.decodeStream(bais, null, options));
            picture = softRef.get();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            imgInfo = null;
            decodeFast = null;
            if (softRef != null) {
                softRef.clear();
                softRef = null;
            }
            try {
                if (bais != null) {
                    bais.close();
                    bais = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return picture;
    }

    private static int calcSampleSize(BitmapFactory.Options options, int reqHeight, int reqWidth) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    /**
     * 生成图片对应的带圆角矩形的图片
     *
     * @param bitmap
     * @param pixels
     * @return
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap
                .createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

    /**
     * 读取图片属性：旋转的角度
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    public static int readPictureDegree(String path) {
        if(TextUtils.isEmpty(path)||!isFile( path)){
            return 0;
        }
        int degree  = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转图片
     * @param angle
     * @param bitmap
     * @return Bitmap
     */
    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();;
        matrix.postRotate(angle);
        // 创建新的图片
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap.recycle();
        return resizedBitmap;
    }

    public static boolean isFile(String path){
        try{
            if(new File(path).isFile()){
                return true;
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return false;
    }

    /**
     * 转成圆形图片
     *
     * @param bitmap
     * @return
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = bitmap.getWidth() / 2;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    /**
     * 按照参数条件进行bitmap的比例伸缩
     *
     * @param bmap
     * @param w
     * @param h
     * @return
     */
    public static Bitmap scaleBitmap(Bitmap bmap, int w, int h) {
        if (bmap == null) {
            return null;
        }
        int width = bmap.getWidth();
        int height = bmap.getHeight();

        float scaleWidth = ((float) w / width);
        float scaleHeight = ((float) h / width);
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap newBm = Bitmap.createBitmap(bmap, 0, 0, width, height, matrix, true);
        return newBm;
    }



    /**
     * bitmap转为base64
     *
     * @param bitmap
     * @return
     */
    public static String bitmapToBase64(Bitmap bitmap, int quality) {
        ByteArrayOutputStream baos = null;
        String result = null;
        try {
            if (bitmap != null) {
                baos = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
                baos.flush();
                baos.close();

                byte[] bitmapBytes = baos.toByteArray();
                result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.flush();
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * bitmap转为base64
     *
     * @param bitmap
     * @return
     */
    public static String bitmapToBase64(Bitmap bitmap) {
        return bitmapToBase64(bitmap, 100);
    }

    /**
     * base64转为bitmap
     *
     * @param base64Data
     * @return
     */
    public static Bitmap base64ToBitmap(String base64Data) {
        byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT);
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    }
}
